using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.XPath;
using Microsoft.SharePoint;
#if MOSS
using Microsoft.SharePoint.Publishing;
#endif
using PS.Practices.Provisioner;
using PS.Practices.SiteBuilder.Features.Schema;

namespace PS.Practices.Util
{
    public static class WebUtil
    {
//Causes Ambiguity between this extension method definition and the one defined in ps.practices
//TODO: Ensure sandbox containment by removing reliance on PS.Practices
#if SANDBOX_TODO
        public static IEnumerable<SPWeb> AsEnumerableHierarchy(this SPWeb web)
        {
            return AsEnumerableHierarchy(web, null, null);
        }

        public static IEnumerable<SPWeb> AsEnumerableHierarchy(this SPWeb web, int webTemplateId)
        {
            return AsEnumerableHierarchy(web, webTemplateId, null);
        }

        public static IEnumerable<SPWeb> AsEnumerableHierarchy(this SPWeb web, int? webTemplateId, short? configurationId)
        {
            yield return web;
            SPWebCollection webs = null;
            if (webTemplateId.HasValue && configurationId.HasValue)
                webs = web.GetSubwebsForCurrentUser(webTemplateId.Value, configurationId.Value);
            else
                if (webTemplateId.HasValue)
                    web.GetSubwebsForCurrentUser(webTemplateId.Value);
                else
                    web.GetSubwebsForCurrentUser();
            foreach (SPWeb child in webs)
            {
                AsEnumerableHierarchy(child, webTemplateId, configurationId);
                child.Dispose();
            }
        }
#endif
        public static void TraverseHierarchy(string webUrl, Action<SPWeb> op)
        {
            using (SPSite site = new SPSite(webUrl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    TraverseHierarchy(web, op);
                }
            }
        }


        public static void TraverseHierarchy(this SPWeb web, Action<SPWeb> op)
        {
            op(web);
            foreach(SPWeb child in web.Webs)
            {
                TraverseHierarchy(child, op);
                child.Dispose();
            }
        }

        public static void TraverseHierarchy(this SPWeb web, Action<SPList> op)
        {
            SPListCollection lists = web.Lists;
            for (int a = 0; a < lists.Count; a++ )
            {
                SPList list = lists[a];
                op(list);
            }
            foreach(SPWeb child in web.Webs)
            {
                TraverseHierarchy(child, op);
                child.Dispose();
            }
        }

        public static void AsSPSite(this Uri uri, Action<SPSite> op)
        {
            using (SPSite site = new SPSite(uri.ToString()))
            {
                op(site);
            }
        }

        public static void AsSPWeb(this Uri uri, Action<SPWeb> op)
        {
            using (SPSite site = new SPSite(uri.ToString()))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    op(web);
                }
            }
        }

        public static void PerformOperation(string webUrl, Action<SPWeb> op)
        {
            using (SPSite site = new SPSite(webUrl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    op(web);
                }
            }
        }

        public static void ApplyScript(SPWeb web, XPathNavigator script)
        {
            Interpreter parser = new Interpreter();
            parser.Process(web, script);
        }

        public static void RestrictSiteTemplates(SPWeb web, IDictionary<string, uint> templates)
        {
            //throw new NotImplementedException("Rewrite the code below");
            //Collection<SPWebTemplate> collSpWebTemplates = new Collection<SPWebTemplate>();
            //PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);

            //web.AllowAllWebTemplates();


            //if (templates == null || templates.Count == 0)
            //{
            //    return;
            //}

            //foreach (string template in templates.Keys)
            //{

            //    SPWebTemplate webTemplate = GetWebTemplate(web, templates[template], template);
            //    if (webTemplate != null)
            //        collSpWebTemplates.Add(webTemplate);
            //}

            //web.SetAvailableCrossLanguageWebTemplates(collSpWebTemplates);
            //// web.SetAvailableWebTemplates(collSpWebTemplates, ((uint)1033));
            //web.AllProperties["__InheritWebTemplates"] = false.ToString();


            //Logger.Info("Restrict begin");
            //if (templates == null || templates.Count == 0)
            //{
            //    Logger.Info("Restrict return");
            //    return;
            //}

            //foreach (var template in templates)
            //{
            //    Logger.Info(string.Format("Restricted name:'{0}', lcid:'{1}'", template.Key, template.Value));
            //}

            //SPWebTemplateCollection existingWebTemps = web.GetAvailableWebTemplates(1033);
            //foreach (SPWebTemplate existingWebTemp in existingWebTemps)
            //{
            //    Logger.Info(string.Format("Exists name:'{0}', lcid:'{1}'", existingWebTemp.Name, existingWebTemp.Lcid));
            //}


            var filters = new Dictionary<uint, List<string>>();
            foreach (var template in templates)
            {
                if (filters.ContainsKey(template.Value))
                {
                    filters[template.Value].Add(template.Key);
                }
                else
                {
                    filters.Add(template.Value, new List<string> { template.Key });
                }
            }

            foreach (var filter in filters)
            {
                Logger.Info(string.Format("Filter lcid:'{0}', count:'{1}'", filter.Key, filter.Value.Count));
                SetAvailableWebTemplates(web, filter.Value, filter.Key);
            }
        }

        public static void SetAvailableWebTemplates(SPWeb web, List<string> restricts, uint lcid)
        {
            var newWebTemps = new Collection<SPWebTemplate>();
            var existingWebTemps = web.GetAvailableWebTemplates(lcid);
            foreach (SPWebTemplate existTemp in existingWebTemps)
            {
                if (!restricts.Contains(existTemp.Name))
                    newWebTemps.Add(existTemp);
            }
            web.SetAvailableWebTemplates(newWebTemps, lcid);
        }

        //public static void RestrictSiteTemplates(SPWeb web, Dictionary<string, uint> templates)
        //{
        //    Collection<SPWebTemplate> collSpWebTemplates = new Collection<SPWebTemplate>();

        //    PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);

        //    SPWebTemplateCollection currentCollection = publishingWeb.GetAvailableCrossLanguageWebTemplates();

        //    //web.AllowAllWebTemplates();
        //    //currentCollection = web.GetAvailableCrossLanguageWebTemplates();

        //    if (templates == null || templates.Count  == 0)
        //    {
        //        return;
        //    }
        //    //SPWebTemplate webTemplate = null;
        //    SPWebTemplateCollection availableCollection = web.Site.OpenWeb().GetAvailableCrossLanguageWebTemplates(); //publishingWeb.ParentPublishingWeb.GetAvailableWebTemplates(((uint)1033));

        //    Collection<SPWebTemplate> allowableSiteTemplates = new Collection<SPWebTemplate>();

        //    //IEnumerable<SPWebTemplate> templatesIEnumerable = templates.Select(t => availableCollection[t.Key]);

        //    //foreach (var spWebTemplate in templatesIEnumerable)
        //    //{
        //    //    allowableSiteTemplates.Add(spWebTemplate);
        //    //}

        //    foreach (string template in templates.Keys)
        //    {

        //        SPWebTemplate webTemplate = GetWebTemplate(web, templates[template], template);
        //        if (webTemplate != null)
        //            allowableSiteTemplates.Add(webTemplate);
        //    }


        //   //publishingWeb.SetAvailableWebTemplates(allowableSiteTemplates, ((uint)1033), true);
        //    publishingWeb.SetAvailableCrossLanguageWebTemplates(allowableSiteTemplates, false);

        //}

        public static SPWebTemplate GetWebTemplate(this SPWeb web, uint lcid, string webTemplateName)
        {
            SPSite site = web.Site;
            SPWebTemplateCollection collection1 = site.GetWebTemplates(lcid);
            SPWebTemplateCollection collection2 = site.GetCustomWebTemplates(lcid);
            SPWebTemplate template1 = null;
            try
            {
                template1 = collection1[webTemplateName];
            }
            catch (ArgumentException)
            {
                try
                {
                    return collection2[webTemplateName];
                }
                catch (ArgumentException)
                {
                    return template1;
                }
            }
            return template1;
        }

        public static void DeleteHierarchy(SPWeb web)
        {
            //var ids = new ArrayList();//web.AsEnumerableHierarchy().Select(w => w.ID).Reverse().ToList();
            var ids = web.AsEnumerableHierarchy().Select(w => w.ID).Reverse().ToList();
            foreach(Guid g in ids)
            {
                using (SPWeb w = web.Site.OpenWeb(g))
                {
                    w.Delete();
                }
            }
        }

#if MOSS
        public static void RestrictPageLayouts(this SPWeb web, IEnumerable<string> strings)
        {
            PublishingWeb pubWeb = PublishingWeb.GetPublishingWeb(web);
            
            PublishingSite pubSite = new PublishingSite(web.Site);
            PageLayoutCollection layouts = pubSite.GetPageLayouts(true);
            IEnumerable<PageLayout> pageLayouts = strings.Select(s => layouts[s]);
            pubWeb.SetAvailablePageLayouts(pageLayouts.ToArray(), false);
            
        }
#endif

        public static void ActivateWebFeatures(SPWeb web, IEnumerable<string> strings)
        {
          
            foreach (var feature in strings)
            {
                web.Features.Add(new Guid(feature));
            }
        }
    }

    public static class CollectionUtil
    {
        public static bool IsEmpty(this ICollection collection)
        {
            return collection != null && collection.Count > 0;
        }
    }
}
